#ifndef PARTICLESWARM_H
#define PARTICLESWARM_H

#include "CostFunction.h"
#include <random>
#include "Particle.h"

using namespace std;

class Particle;

enum SWARM_MODE{
	SWARM_MODE_NEW,
	SWARM_MODE_TRACKING
};

class ParticleSwarm
{
public:
	//------------------------------------------------------
	/// Indexer to return a particle?
	Particle& operator[](int i);
	ParticleSwarm();
	~ParticleSwarm();

	CostFunction* swCostFunction;

	// Range of dimensions
	vector<double> MinRange;
	vector<double> MaxRange;
	vector<double> RandomRange;
	void setWristRange(double x, double y, double z, double size_x, double size_y, double size_z);

	int swarmSize;
	int swarmDimension;

	//------------------------------------------------------
	/// The current (global) best position of the swarm
	vector<double> current_gBestPosition();

	//------------------------------------------------------
	/// The current (global) best cost of the swarm
	double current_gBestCost();

	//------------------------------------------------------
	/// Init the swarm
	void setPotentialParticle(vector<double> expectedDofs);
	void startSwarm();
	void endSwarm();
	//------------------------------------------------------
	/// Execute one evolution step
	virtual void iteration();

	// Randomize particles
	void randomize(double randPercent, int lowBoundDim, int highBoundDim);
#pragma region PARTICLE_OBJ
	/// Particles
	vector<Particle*> swParticles;

	// Inertia coefficient (w)
	double Momentum;

	// Cognitive factor (c1)
	double TendencyToOwnBest;

	// Social factors (c2)
	double TendencyToGlobalBest;

	/// PercentMaximumVelocityOfSearchSpace?vmax=k*xmax,k value?
	double PercentMaximumVelocityOfSearchSpace;

	/// UseGlobalOptimum?Whether to adopt a global optimization strategy, default true?
	bool UseGlobalOptimum;

	/// Best position of the whole swarm (Global best position)
	vector<double> gBestPosition;
	double gBestCost;
#pragma endregion PARTICLE_OBJ

protected:
	//Random _rnd;

private:
	/// Sort particle according to the cost (fitness), from small to large
	void sortParticles();
	
	/// Random number generator 
	std::random_device rd;
	std::mt19937 gen;
	std::uniform_real_distribution<> uniDis;
	std::uniform_real_distribution<> uniDis_minus;

	void setRandomParticle();
};

#endif